#include <stdio.h>

typedef struct sGeneratePacker
{
	unsigned char package[264 + 256];
} GeneratePacker_t;

typedef GeneratePacker_t *GeneratePacker_ptr;

typedef struct sGenerateParser
{
	int stage;
	int idx;
	unsigned char msg_id;
	int msg_len;
	unsigned char payload[264];
	unsigned short crc16;
	unsigned int pkg_cnt;
	unsigned int err_cnt;
} GenerateParser_t;

typedef GenerateParser_t *GenerateParser_ptr;




   const static unsigned short crc16_R_table[256] = {
        0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
        0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
        0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
        0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
        0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
        0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
        0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
        0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
        0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
        0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
        0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
        0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
        0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
        0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
        0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
        0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
        0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
        0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
        0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
        0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
        0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
        0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
        0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
        0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
        0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
        0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
        0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
        0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
        0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
        0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
        0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
        0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
    };






void hello()
{
	printf("hello world!\n");
}

void test()
{
	hello();
	printf("test \n");
}

/**
 * @brief 打包数据
 *
 * @param packer 打包器指针
 * @param msg_id 消息ID
 * @param msg_len 消息长度
 * @param msg 消息数据指针
 * @return int 打包后的消息长度
 *
 * @details
 * 首先检查消息长度 msg_len 是否小于等于252字节。这个限制可能是由于协议或缓冲区大小的限制。
 * 如果消息长度符合要求，则按照信息帧格式进行打包。
 * 信息帧格式为：
 * 0xEB 0x90 msg_id msg_len msg_data CRC16 0x5A padding
 * 其中 padding 是用于对消息长度进行对齐的填充字节，通过在消息末尾添加0x5A，直到达到4的倍数长度。
 * CRC16 是使用 MakeCRC_R_LookupTable 函数计算从 msg_data 开始、长度为 msg_len 的消息内容的CRC校验和。
 */
// int GeneratePacker_pack(GeneratePacker_ptr packer, unsigned char msg_id,
// 						unsigned msg_len, unsigned char msg[])
// {
// 	unsigned short crc16;
// 	int idx;

// 	if (msg_len <= 252)
// 	{
// 		packer->package[0] = 0xEB;
// 		packer->package[1] = 0x90;
// 		packer->package[2] = msg_id;
// 		packer->package[3] = msg_len;
// 		memset_sa(&(packer->package[4]), 0, msg_len);
// 		memcpy_sa(&packer->package[4], msg, msg_len);

// 		crc16 = MakeCRC_R_LookupTable(&packer->package[4], msg_len);

// 		idx = msg_len + 4;
// 		packer->package[idx++] = (crc16 & 0xFF);
// 		packer->package[idx++] = ((crc16 >> 8) & 0xFF);

// 		while ((idx % 4) != 0)
// 		{
// 			packer->package[idx++] = 0x5A;
// 		}
// 	}

// 	return idx;
// }

unsigned short MakeCRC_R_LookupTable(unsigned char* message, unsigned int len)
{
    unsigned short crc_reg = 0xffff;
    //  unsigned short crc_reg = 0;
    while (len--)
        crc_reg = (crc_reg >> 8) ^ crc16_R_table[(crc_reg ^ *message++) & 0xff];
    return (crc_reg ^ 0xffff);
}








/**
 * @brief 通用数据解析器
 * @param parser: 指向解析器的指针
 * @param c: 接收到的字符
 * @return 解析结果，如果解析成功，返回消息的总长度；如果解析失败或者消息尚未完全接收，返回0。
 * @note 该函数是一个状态机解析器，根据当前的状态和输入的字符决定下一步操作。
 * @details 该函数接收一个字符，并根据当前的解析器状态进行解析。
 *          如果输入的字符是特定的起始标志0xEB，解析器将进入下一个状态并将字符存储到 payload 数组中。
 *          如果输入的字符不是0x90，解析器状态重置为0。
 *          在状态1，接收第二个字符，如果是0x90，同样将字符存储并进入下一个状态。
 *          在状态2，接收并存储消息ID。
 *          在状态3，接收并存储消息长度，并将消息长度调整为实际长度加上4（考虑到起始标志、消息ID和长度本身占用的字节）。
 *          在状态4，接收消息内容直到达到预定的消息长度。接收完消息内容后，开始接收CRC校验和的第一个字节。
 *          在状态5，接收CRC校验和的第二个字节，并将之前接收的CRC校验和的第一个字节与第二个字节组合成16位的CRC校验和。
 *          然后，使用 MakeCRC_R_LookupTable 函数计算消息内容的CRC校验和，并与接收到的CRC校验和进行比较。
 *          如果计算出的CRC校验和与接收到的校验和相匹配，表示消息正确无误，更新 pkg_cnt 计数器，并将 ret 设置为消息的总长度，表示解析成功。
 *          如果校验和不匹配，增加错误计数 err_cnt ，表示解析失败。
 *          最后，函数返回 ret ，如果解析成功， ret 为消息的总长度；如果解析失败或者消息尚未完全接收， ret 为0。
 */
int GenerateParser_parse_char(GenerateParser_ptr parser, unsigned char c)
{
	int ret;
	/***初始化返回值**： ret 被初始化为0，表示默认情况下没有特殊的解析结果*/
	ret = 0;
	/* **状态机**：解析器通过 parser->stage 变量维护一个状态机，根据当前的状态和输入的字符决定下一步操作*/
	switch (parser->stage)
	{
	/* - 在状态0，函数检查输入字符是否为特定的起始标志0xEB。如果是，将字符存储到 payload 数组中，并进入下一个状态。 */
	case 0:
		if (c == 0xEB)
		{
			parser->idx = 0;
			parser->payload[parser->idx++] = c;
			parser->stage++;
		}
		break;
	/* 在状态1，检查第二个字符是否为0x90。如果是，同样将字符存储并进入下一个状态。如果不是，解析器状态重置为0。 */
	case 1:
		if (c == 0x90)
		{
			parser->payload[parser->idx++] = c;
			parser->stage++;
		}
		else
		{
			parser->stage = 0;
		}
		break;
	/*在状态2，接收并存储消息ID。*/
	case 2:
		parser->payload[parser->idx++] = c;
		parser->msg_id = c;
		parser->stage++;
		break;
	/*在状态3，接收并存储消息长度，并将消息长度调整为实际长度加上4（考虑到起始标志、消息ID和长度本身占用的字节）。 */
	case 3:
		parser->payload[parser->idx++] = c;
		parser->msg_len = c + 4;
		parser->stage++;
		break;
	/*在状态4，接收消息内容直到达到预定的消息长度。接收完消息内容后，开始接收CRC校验和的第一个字节。*/
	case 4:
		if (parser->idx < parser->msg_len)
		{
			parser->payload[parser->idx++] = c;
		}
		else
		{
			parser->crc16 = c;
			parser->payload[parser->idx++] = c;
			parser->stage++;
		}
		break;
	/*在状态5，接收CRC校验和的第二个字节，并将之前接收的CRC校验和的第一个字节与第二个字节组合成16位的CRC校验和。然后，使用 MakeCRC_R_LookupTable 函数计算消息内容的CRC校验和，并与接收到的CRC校验和进行比较。 */
	case 5:
		parser->crc16 += c * 256;
		parser->payload[parser->idx++] = c;
		/*如果计算出的CRC校验和与接收到的校验和相匹配，表示消息正确无误，更新 pkg_cnt 计数器，并将 ret 设置为消息的总长度，表示解析成功。 */
		if (MakeCRC_R_LookupTable(parser->payload + 4, parser->msg_len - 4) ==
			parser->crc16)
		{
			ret = parser->idx;
			parser->pkg_cnt++;
		}
		else
		{
			// ret = parser->idx;
			/*如果校验和不匹配，增加错误计数 err_cnt ，表示解析失败。 */
			parser->err_cnt++;
		}
		parser->stage = 0;
		break;
	default:
		parser->stage = 0;
		break;
	}
	/*. **返回解析结果**：最后，函数返回 ret ，如果解析成功， ret 为消息的总长度；如果解析失败或者消息尚未完全接收， ret 为0。 */
	return ret;
}

void main()
{
	hello();
	hello();
	test();
	test();
	test();
}